from datetime import datetime
from typing import Optional, Dict, Any
from database import db


class Device:
    """设备模型"""
    
    COLLECTION = 'devices'
    
    @staticmethod
    def create(device_data: Dict[str, Any]) -> Dict[str, Any]:
        """创建设备"""
        device = {
            'deviceId': device_data['deviceId'],
            'deviceName': device_data.get('deviceName', ''),
            'status': 'offline',
            'lastOnlineTime': None,
            'lastHeartbeatTime': None,
            'ipAddress': device_data.get('ipAddress', ''),
            'createdAt': datetime.utcnow(),
            'updatedAt': datetime.utcnow()
        }
        db.db[Device.COLLECTION].insert_one(device)
        device['_id'] = str(device['_id'])
        return device
    
    @staticmethod
    def find_by_id(device_id: str) -> Optional[Dict[str, Any]]:
        """根据ID查找设备"""
        device = db.db[Device.COLLECTION].find_one({'deviceId': device_id})
        if device:
            device['_id'] = str(device['_id'])
        return device
    
    @staticmethod
    def find_all(filters: Optional[Dict] = None, skip: int = 0, limit: int = 100) -> list:
        """查找所有设备"""
        query = filters or {}
        devices = list(db.db[Device.COLLECTION].find(query).skip(skip).limit(limit).sort('updatedAt', -1))
        for device in devices:
            device['_id'] = str(device['_id'])
        return devices
    
    @staticmethod
    def count(filters: Optional[Dict] = None) -> int:
        """统计设备数量"""
        query = filters or {}
        return db.db[Device.COLLECTION].count_documents(query)
    
    @staticmethod
    def update(device_id: str, update_data: Dict[str, Any]) -> bool:
        """更新设备信息"""
        update_data['updatedAt'] = datetime.utcnow()
        result = db.db[Device.COLLECTION].update_one(
            {'deviceId': device_id},
            {'$set': update_data}
        )
        return result.modified_count > 0
    
    @staticmethod
    def delete(device_id: str) -> bool:
        """删除设备"""
        result = db.db[Device.COLLECTION].delete_one({'deviceId': device_id})
        return result.deleted_count > 0
    
    @staticmethod
    def update_status(device_id: str, status: str, ip_address: Optional[str] = None) -> bool:
        """更新设备状态"""
        update_data = {
            'status': status,
            'lastHeartbeatTime': datetime.utcnow(),
            'updatedAt': datetime.utcnow()
        }
        
        if status == 'online' and ip_address:
            update_data['lastOnlineTime'] = datetime.utcnow()
            update_data['ipAddress'] = ip_address
        
        result = db.db[Device.COLLECTION].update_one(
            {'deviceId': device_id},
            {'$set': update_data}
        )
        return result.modified_count > 0 or result.matched_count > 0
    
    @staticmethod
    def get_statistics() -> Dict[str, int]:
        """获取设备统计信息"""
        total = Device.count()
        online = Device.count({'status': 'online'})
        offline = Device.count({'status': 'offline'})
        
        return {
            'total': total,
            'online': online,
            'offline': offline,
            'onlineRate': round(online / total * 100, 2) if total > 0 else 0
        }


class HeartbeatLog:
    """心跳日志模型"""
    
    COLLECTION = 'heartbeat_logs'
    
    @staticmethod
    def create(device_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
        """创建心跳日志"""
        log = {
            'deviceId': device_id,
            'timestamp': datetime.utcnow(),
            'payload': payload
        }
        result = db.db[HeartbeatLog.COLLECTION].insert_one(log)
        log['_id'] = str(result.inserted_id)
        return log
    
    @staticmethod
    def find_by_device(device_id: str, skip: int = 0, limit: int = 100) -> list:
        """查找设备的心跳日志"""
        logs = list(db.db[HeartbeatLog.COLLECTION].find(
            {'deviceId': device_id}
        ).skip(skip).limit(limit).sort('timestamp', -1))
        
        for log in logs:
            log['_id'] = str(log['_id'])
        return logs
    
    @staticmethod
    def count_by_device(device_id: str) -> int:
        """统计设备心跳日志数量"""
        return db.db[HeartbeatLog.COLLECTION].count_documents({'deviceId': device_id})
    
    @staticmethod
    def delete_old_logs(days: int = 7):
        """删除旧的心跳日志"""
        from datetime import timedelta
        cutoff_date = datetime.utcnow() - timedelta(days=days)
        result = db.db[HeartbeatLog.COLLECTION].delete_many(
            {'timestamp': {'$lt': cutoff_date}}
        )
        return result.deleted_count


class DeviceLog:
    """设备日志模型"""
    
    COLLECTION = 'device_logs'
    
    @staticmethod
    def create(device_id: str, event_type: str, message: str) -> Dict[str, Any]:
        """创建设备日志"""
        log = {
            'deviceId': device_id,
            'eventType': event_type,
            'message': message,
            'timestamp': datetime.utcnow()
        }
        result = db.db[DeviceLog.COLLECTION].insert_one(log)
        log['_id'] = str(result.inserted_id)
        return log
    
    @staticmethod
    def find_by_device(device_id: str, event_type: Optional[str] = None, 
                      skip: int = 0, limit: int = 100) -> list:
        """查找设备的日志"""
        query = {'deviceId': device_id}
        if event_type:
            query['eventType'] = event_type
        
        logs = list(db.db[DeviceLog.COLLECTION].find(query).skip(skip).limit(limit).sort('timestamp', -1))
        for log in logs:
            log['_id'] = str(log['_id'])
        return logs
    
    @staticmethod
    def count_by_device(device_id: str, event_type: Optional[str] = None) -> int:
        """统计设备日志数量"""
        query = {'deviceId': device_id}
        if event_type:
            query['eventType'] = event_type
        return db.db[DeviceLog.COLLECTION].count_documents(query)
    
    @staticmethod
    def delete_old_logs(days: int = 30):
        """删除旧的设备日志"""
        from datetime import timedelta
        cutoff_date = datetime.utcnow() - timedelta(days=days)
        result = db.db[DeviceLog.COLLECTION].delete_many(
            {'timestamp': {'$lt': cutoff_date}}
        )
        return result.deleted_count


class Ward:
    """病房模型"""
    
    COLLECTION = 'wards'
    
    @staticmethod
    def create(ward_data: Dict[str, Any]) -> Dict[str, Any]:
        """创建病房"""
        ward = {
            'wardName': ward_data['wardName'],
            'wardNumber': ward_data.get('wardNumber', ''),
            'floor': ward_data.get('floor', ''),
            'building': ward_data.get('building', ''),
            'description': ward_data.get('description', ''),
            'createdAt': datetime.utcnow(),
            'updatedAt': datetime.utcnow()
        }
        result = db.db[Ward.COLLECTION].insert_one(ward)
        ward['_id'] = str(result.inserted_id)
        return ward
    
    @staticmethod
    def find_by_id(ward_id: str) -> Optional[Dict[str, Any]]:
        """根据ID查找病房"""
        from bson import ObjectId
        try:
            ward = db.db[Ward.COLLECTION].find_one({'_id': ObjectId(ward_id)})
            if ward:
                ward['_id'] = str(ward['_id'])
            return ward
        except:
            return None
    
    @staticmethod
    def find_all(filters: Optional[Dict] = None, skip: int = 0, limit: int = 100) -> list:
        """查找所有病房"""
        query = filters or {}
        wards = list(db.db[Ward.COLLECTION].find(query).skip(skip).limit(limit).sort('createdAt', -1))
        for ward in wards:
            ward['_id'] = str(ward['_id'])
        return wards
    
    @staticmethod
    def count(filters: Optional[Dict] = None) -> int:
        """统计病房数量"""
        query = filters or {}
        return db.db[Ward.COLLECTION].count_documents(query)
    
    @staticmethod
    def update(ward_id: str, update_data: Dict[str, Any]) -> bool:
        """更新病房信息"""
        from bson import ObjectId
        try:
            update_data['updatedAt'] = datetime.utcnow()
            result = db.db[Ward.COLLECTION].update_one(
                {'_id': ObjectId(ward_id)},
                {'$set': update_data}
            )
            return result.modified_count > 0
        except:
            return False
    
    @staticmethod
    def delete(ward_id: str) -> bool:
        """删除病房"""
        from bson import ObjectId
        try:
            result = db.db[Ward.COLLECTION].delete_one({'_id': ObjectId(ward_id)})
            return result.deleted_count > 0
        except:
            return False


class Bed:
    """床位模型"""
    
    COLLECTION = 'beds'
    
    @staticmethod
    def create(bed_data: Dict[str, Any]) -> Dict[str, Any]:
        """创建床位"""
        bed = {
            'wardId': bed_data['wardId'],
            'bedNumber': bed_data['bedNumber'],
            'bedName': bed_data.get('bedName', ''),
            'deviceId': bed_data.get('deviceId', None),
            'status': bed_data.get('status', 'available'),  # available/occupied
            'description': bed_data.get('description', ''),
            'createdAt': datetime.utcnow(),
            'updatedAt': datetime.utcnow()
        }
        result = db.db[Bed.COLLECTION].insert_one(bed)
        bed['_id'] = str(result.inserted_id)
        return bed
    
    @staticmethod
    def find_by_id(bed_id: str) -> Optional[Dict[str, Any]]:
        """根据ID查找床位"""
        from bson import ObjectId
        try:
            bed = db.db[Bed.COLLECTION].find_one({'_id': ObjectId(bed_id)})
            if bed:
                bed['_id'] = str(bed['_id'])
            return bed
        except:
            return None
    
    @staticmethod
    def find_by_ward(ward_id: str) -> list:
        """根据病房ID查找床位"""
        beds = list(db.db[Bed.COLLECTION].find({'wardId': ward_id}).sort('bedNumber', 1))
        for bed in beds:
            bed['_id'] = str(bed['_id'])
        return beds
    
    @staticmethod
    def find_all(filters: Optional[Dict] = None, skip: int = 0, limit: int = 100) -> list:
        """查找所有床位"""
        query = filters or {}
        beds = list(db.db[Bed.COLLECTION].find(query).skip(skip).limit(limit).sort('bedNumber', 1))
        for bed in beds:
            bed['_id'] = str(bed['_id'])
        return beds
    
    @staticmethod
    def count(filters: Optional[Dict] = None) -> int:
        """统计床位数量"""
        query = filters or {}
        return db.db[Bed.COLLECTION].count_documents(query)
    
    @staticmethod
    def update(bed_id: str, update_data: Dict[str, Any]) -> bool:
        """更新床位信息"""
        from bson import ObjectId
        try:
            update_data['updatedAt'] = datetime.utcnow()
            result = db.db[Bed.COLLECTION].update_one(
                {'_id': ObjectId(bed_id)},
                {'$set': update_data}
            )
            return result.modified_count > 0 or result.matched_count > 0
        except:
            return False
    
    @staticmethod
    def delete(bed_id: str) -> bool:
        """删除床位"""
        from bson import ObjectId
        try:
            result = db.db[Bed.COLLECTION].delete_one({'_id': ObjectId(bed_id)})
            return result.deleted_count > 0
        except:
            return False
    
    @staticmethod
    def bind_device(bed_id: str, device_id: str) -> bool:
        """绑定设备到床位"""
        from bson import ObjectId
        try:
            result = db.db[Bed.COLLECTION].update_one(
                {'_id': ObjectId(bed_id)},
                {'$set': {'deviceId': device_id, 'status': 'occupied', 'updatedAt': datetime.utcnow()}}
            )
            return result.modified_count > 0
        except:
            return False
    
    @staticmethod
    def unbind_device(bed_id: str) -> bool:
        """解绑设备"""
        from bson import ObjectId
        try:
            result = db.db[Bed.COLLECTION].update_one(
                {'_id': ObjectId(bed_id)},
                {'$set': {'deviceId': None, 'status': 'available', 'updatedAt': datetime.utcnow()}}
            )
            return result.modified_count > 0
        except:
            return False
    
    @staticmethod
    def find_by_device(device_id: str) -> Optional[Dict[str, Any]]:
        """根据设备ID查找床位"""
        bed = db.db[Bed.COLLECTION].find_one({'deviceId': device_id})
        if bed:
            bed['_id'] = str(bed['_id'])
        return bed
